package com.qiangesoft.image.utils;

import org.springframework.util.Assert;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.stream.ImageOutputStream;
import java.awt.*;
import java.awt.color.ColorSpace;
import java.awt.image.BufferedImage;
import java.awt.image.ColorConvertOp;
import java.io.*;
import java.util.Iterator;

/**
 * 图片操作
 *
 * @author qiangesoft
 * @date 2024-04-26
 */
public class ImageOperateUtil {

    /**
     * 图片格式转换
     *
     * @param sourcePath
     * @param targetPath
     * @throws IOException
     */
    public static void convert(String sourcePath, String targetPath) throws IOException {
        String fileType = targetPath.substring(targetPath.lastIndexOf(".") + 1);
        try (FileInputStream fis = new FileInputStream(sourcePath);
             ImageOutputStream ios = ImageIO.createImageOutputStream(new File(targetPath))) {
            convert(fis, ios, fileType);
        }
    }

    /**
     * 图片格式转换
     *
     * @param file
     * @param outputStream
     * @param fileType
     * @throws IOException
     */
    public static void convert(MultipartFile file, OutputStream outputStream, String fileType) throws IOException {
        try (ImageOutputStream ios = ImageIO.createImageOutputStream(outputStream);
             InputStream inputStream = file.getInputStream()) {
            convert(inputStream, ios, fileType);
        }
    }

    private static void convert(InputStream inputStream, ImageOutputStream outputStream, String fileType) throws IOException {
        // 获取ImageWriter
        Iterator<ImageWriter> writerIterator = ImageIO.getImageWritersByFormatName(fileType);
        Assert.isTrue(writerIterator.hasNext(), "图片文件格式错误");
        ImageWriter writer = writerIterator.next();

        // 写入图片
        writer.setOutput(outputStream);
        BufferedImage image = ImageIO.read(inputStream);
        writer.write(null, new IIOImage(image, null, null), null);
    }

    /**
     * 压缩图片
     *
     * @param sourcePath
     * @param targetPath
     * @param quality
     * @throws IOException
     */
    public static void compress(String sourcePath, String targetPath, float quality) throws IOException {
        String fileType = targetPath.substring(targetPath.lastIndexOf(".") + 1);
        try (FileInputStream fis = new FileInputStream(sourcePath);
             ImageOutputStream ios = ImageIO.createImageOutputStream(new File(targetPath))) {
            compress(fis, ios, fileType, quality);
        }
    }

    /**
     * 压缩图片
     *
     * @param file
     * @param outputStream
     * @param quality
     * @throws IOException
     */
    public static void compress(MultipartFile file, OutputStream outputStream, float quality) throws IOException {
        String originalFilename = file.getOriginalFilename();
        Assert.notNull(originalFilename, "文件非法");
        String fileType = originalFilename.substring(originalFilename.lastIndexOf(".") + 1);
        try (ImageOutputStream ios = ImageIO.createImageOutputStream(outputStream);
             InputStream inputStream = file.getInputStream()) {
            compress(inputStream, ios, fileType, quality);
        }
    }

    private static void compress(InputStream inputStream, ImageOutputStream outputStream, String fileType, float quality) throws IOException {
        // 获取ImageWriter
        Iterator<ImageWriter> writerIterator = ImageIO.getImageWritersByFormatName(fileType);
        Assert.isTrue(writerIterator.hasNext(), "图片文件格式错误");
        ImageWriter writer = writerIterator.next();

        // 设置写入参数
        ImageWriteParam iwp = writer.getDefaultWriteParam();
        iwp.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
        iwp.setCompressionQuality(quality);

        // 写入图片
        writer.setOutput(outputStream);
        BufferedImage image = ImageIO.read(inputStream);
        writer.write(null, new IIOImage(image, null, null), iwp);
    }

    /**
     * 裁剪图片
     *
     * @param sourcePath
     * @param targetPath
     * @param width
     * @param height
     * @throws IOException
     */
    public static void crop(String sourcePath, String targetPath, int width, int height) throws IOException {
        crop(sourcePath, targetPath, 0, 0, width, height);
    }

    public static void crop(String sourcePath, String targetPath, int x, int y, int width, int height) throws IOException {
        String targetType = targetPath.substring(targetPath.lastIndexOf(".") + 1);
        try (FileInputStream fis = new FileInputStream(sourcePath);
             FileOutputStream fos = new FileOutputStream(targetPath)) {
            crop(fis, fos, targetType, x, y, width, height);
        }
    }

    /**
     * 裁剪图片
     *
     * @param file
     * @param outputStream
     * @param width
     * @param height
     * @throws IOException
     */
    public static void crop(MultipartFile file, OutputStream outputStream, int width, int height) throws IOException {
        crop(file, outputStream, 0, 0, width, height);
    }

    public static void crop(MultipartFile file, OutputStream outputStream, int x, int y, int width, int height) throws IOException {
        String originalFilename = file.getOriginalFilename();
        Assert.notNull(originalFilename, "文件非法");
        String sourceType = originalFilename.substring(originalFilename.lastIndexOf(".") + 1);
        try (InputStream inputStream = file.getInputStream()) {
            crop(inputStream, outputStream, sourceType, x, y, width, height);
        }
    }

    private static void crop(InputStream inputStream, OutputStream outputStream, String targetType, int x, int y, int width, int height) throws IOException {
        // 读取图片
        BufferedImage image = ImageIO.read(inputStream);
        int maxWidth = image.getWidth();
        Assert.isTrue(maxWidth > x + width, "图片宽度不足");
        int maxHeight = image.getHeight();
        Assert.isTrue(maxHeight > y + height, "图片高度不足");

        // 裁剪图片
        BufferedImage destImage = image.getSubimage(x, y, width, height);

        // 保存新图片
        ImageIO.write(destImage, targetType, outputStream);
    }

    /**
     * 按倍率缩小图片
     *
     * @param sourcePath
     * @param targetPath
     * @param ratio
     * @throws IOException
     */
    public static void reduceByRatio(String sourcePath, String targetPath, int ratio) throws IOException {
        String fileType = targetPath.substring(targetPath.lastIndexOf(".") + 1);
        try (FileInputStream inputStream = new FileInputStream(sourcePath);
             FileOutputStream outputStream = new FileOutputStream(targetPath)) {
            reduceByRatio(inputStream, outputStream, ratio, fileType);
        }
    }

    /**
     * 按倍率缩小图片
     *
     * @param file
     * @param outputStream
     * @param ratio
     * @throws IOException
     */
    public static void reduceByRatio(MultipartFile file, OutputStream outputStream, int ratio) throws IOException {
        String originalFilename = file.getOriginalFilename();
        Assert.notNull(originalFilename, "文件非法");
        String fileType = originalFilename.substring(originalFilename.lastIndexOf(".") + 1);
        try (InputStream inputStream = file.getInputStream()) {
            reduceByRatio(inputStream, outputStream, ratio, fileType);
        }
    }

    private static void reduceByRatio(InputStream inputStream, OutputStream outputStream, int ratio, String sourceType) throws IOException {
        // 构造Image对象
        BufferedImage sourceImage = ImageIO.read(inputStream);
        int width = sourceImage.getWidth() / ratio;
        int height = sourceImage.getHeight() / ratio;

        resize(sourceImage, outputStream, width, height, sourceType);
    }

    /**
     * 按倍率放大图片
     *
     * @param sourcePath
     * @param targetPath
     * @param ratio
     * @throws IOException
     */
    public static void enlargeByRatio(String sourcePath, String targetPath, int ratio) throws IOException {
        String fileType = targetPath.substring(targetPath.lastIndexOf(".") + 1);
        try (FileInputStream inputStream = new FileInputStream(sourcePath);
             FileOutputStream outputStream = new FileOutputStream(targetPath)) {
            enlargeByRatio(inputStream, outputStream, ratio, fileType);
        }
    }

    /**
     * 按倍率放大图片
     *
     * @param file
     * @param outputStream
     * @param ratio
     * @throws IOException
     */
    public static void enlargeByRatio(MultipartFile file, OutputStream outputStream, int ratio) throws IOException {
        String originalFilename = file.getOriginalFilename();
        Assert.notNull(originalFilename, "文件非法");
        String fileType = originalFilename.substring(originalFilename.lastIndexOf(".") + 1);
        try (InputStream inputStream = file.getInputStream()) {
            enlargeByRatio(inputStream, outputStream, ratio, fileType);
        }
    }

    private static void enlargeByRatio(InputStream inputStream, OutputStream outputStream, int ratio, String fileType) throws IOException {
        // 构造Image对象
        BufferedImage sourceImage = ImageIO.read(inputStream);
        int width = sourceImage.getWidth() * ratio;
        int height = sourceImage.getHeight() * ratio;

        resize(sourceImage, outputStream, width, height, fileType);
    }

    /**
     * 按倍率放大图片
     *
     * @param sourcePath
     * @param targetPath
     * @param width
     * @param height
     * @throws IOException
     */
    public static void resize(String sourcePath, String targetPath, int width, int height) throws IOException {
        String fileType = targetPath.substring(targetPath.lastIndexOf(".") + 1);
        try (FileInputStream inputStream = new FileInputStream(sourcePath);
             FileOutputStream outputStream = new FileOutputStream(targetPath)) {
            // 构造Image对象
            BufferedImage sourceImage = ImageIO.read(inputStream);
            resize(sourceImage, outputStream, width, height, fileType);
        }
    }

    /**
     * 按倍率放大图片
     *
     * @param file
     * @param outputStream
     * @param width
     * @param height
     * @throws IOException
     */
    public static void resize(MultipartFile file, OutputStream outputStream, int width, int height) throws IOException {
        String originalFilename = file.getOriginalFilename();
        Assert.notNull(originalFilename, "文件非法");
        String fileType = originalFilename.substring(originalFilename.lastIndexOf(".") + 1);
        try (InputStream inputStream = file.getInputStream()) {
            // 构造Image对象
            BufferedImage sourceImage = ImageIO.read(inputStream);
            resize(sourceImage, outputStream, width, height, fileType);
        }
    }

    private static void resize(BufferedImage sourceImage, OutputStream outputStream, int width, int height, String fileType) throws IOException {
        // 创建图片
        BufferedImage targetImage = new BufferedImage(width, height, sourceImage.getType());
        Graphics2D g2d = targetImage.createGraphics();

        // 设置宽高
        g2d.drawImage(sourceImage, 0, 0, width, height, null);
        g2d.dispose();

        // 保存新图片
        ImageIO.write(targetImage, fileType, outputStream);
    }

    /**
     * 图片灰化
     *
     * @param sourcePath
     * @param targetPath
     * @throws IOException
     */
    public static void gray(String sourcePath, String targetPath) throws IOException {
        String fileType = targetPath.substring(targetPath.lastIndexOf(".") + 1);
        try (FileInputStream inputStream = new FileInputStream(sourcePath);
             FileOutputStream outputStream = new FileOutputStream(targetPath)) {
            gray(inputStream, outputStream, fileType);
        }
    }

    /**
     * 图片灰化
     *
     * @param file
     * @param outputStream
     * @throws IOException
     */
    public static void gray(MultipartFile file, OutputStream outputStream) throws IOException {
        String originalFilename = file.getOriginalFilename();
        Assert.notNull(originalFilename, "文件非法");
        String fileType = originalFilename.substring(originalFilename.lastIndexOf(".") + 1);
        try (InputStream inputStream = file.getInputStream()) {
            gray(inputStream, outputStream, fileType);
        }
    }

    private static void gray(InputStream inputStream, OutputStream outputStream, String fileType) throws IOException {
        // 读取图片
        BufferedImage bufferedImage = ImageIO.read(inputStream);

        // 灰化
        ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_GRAY);
        ColorConvertOp op = new ColorConvertOp(cs, null);
        BufferedImage newBufferedImage = op.filter(bufferedImage, null);

        // 保存新图片
        ImageIO.write(newBufferedImage, fileType, outputStream);
    }

    /**
     * 图片添加文字水印
     *
     * @param sourcePath
     * @param targetPath
     * @param font
     * @param color
     * @param x
     * @param y
     * @param watermarkText
     * @throws IOException
     */
    public static void watermarkText(String sourcePath, String targetPath, Font font, Color color, int x, int y, String watermarkText) throws IOException {
        String fileType = targetPath.substring(targetPath.lastIndexOf(".") + 1);
        try (FileInputStream inputStream = new FileInputStream(sourcePath);
             FileOutputStream outputStream = new FileOutputStream(targetPath)) {
            watermarkText(inputStream, outputStream, font, color, x, y, watermarkText, fileType);
        }
    }

    /**
     * 图片添加文字水印
     *
     * @param file
     * @param outputStream
     * @param font
     * @param color
     * @param x
     * @param y
     * @param watermarkText
     * @throws IOException
     */
    public static void watermarkText(MultipartFile file, OutputStream outputStream, Font font, Color color, int x, int y, String watermarkText) throws IOException {
        String originalFilename = file.getOriginalFilename();
        Assert.notNull(originalFilename, "文件非法");
        String fileType = originalFilename.substring(originalFilename.lastIndexOf(".") + 1);
        try (InputStream inputStream = file.getInputStream()) {
            watermarkText(inputStream, outputStream, font, color, x, y, watermarkText, fileType);
        }
    }

    private static void watermarkText(InputStream inputStream, OutputStream outputStream, Font font, Color color, int x, int y, String watermarkText, String fileType) throws IOException {
        // 读取图片
        BufferedImage image = ImageIO.read(inputStream);
        Graphics2D g2d = image.createGraphics();

        // 设置文字字体、样式
        g2d.setFont(font);
        g2d.setColor(color);
        g2d.drawString(watermarkText, x, y);
        g2d.dispose();

        // 保存新图片
        ImageIO.write(image, fileType, outputStream);
    }

    /**
     * 图片添加图片水印
     *
     * @param sourcePath
     * @param appendSourcePath
     * @param targetPath
     * @param x
     * @param y
     * @param width
     * @param height
     * @throws IOException
     */
    public static void watermarkImage(String sourcePath, String appendSourcePath, String targetPath, int x, int y, int width, int height) throws IOException {
        String fileType = targetPath.substring(targetPath.lastIndexOf(".") + 1);
        try (FileInputStream inputStream = new FileInputStream(sourcePath);
             FileInputStream appendInputStream = new FileInputStream(appendSourcePath);
             FileOutputStream outputStream = new FileOutputStream(targetPath)) {
            watermarkImage(inputStream, appendInputStream, outputStream, x, y, width, height, fileType);
        }
    }

    /**
     * 图片添加图片水印
     *
     * @param file
     * @param appendFile
     * @param outputStream
     * @param x
     * @param y
     * @param width
     * @param height
     * @throws IOException
     */
    public static void watermarkImage(MultipartFile file, MultipartFile appendFile, OutputStream outputStream, int x, int y, int width, int height) throws IOException {
        String originalFilename = file.getOriginalFilename();
        Assert.notNull(originalFilename, "文件非法");
        String fileType = originalFilename.substring(originalFilename.lastIndexOf(".") + 1);
        try (InputStream inputStream = file.getInputStream();
             InputStream appendInputStream = appendFile.getInputStream()) {
            watermarkImage(inputStream, appendInputStream, outputStream, x, y, width, height, fileType);
        }
    }

    private static void watermarkImage(InputStream inputStream, InputStream appendInputStream, OutputStream outputStream, int x, int y, int width, int height, String fileType) throws IOException {
        // 读取图片
        BufferedImage image = ImageIO.read(inputStream);
        Graphics2D g2d = image.createGraphics();

        // 设置水印图片的起始x/y坐标、宽度、高度
        BufferedImage appendImage = ImageIO.read(appendInputStream);
        g2d.drawImage(appendImage, x, y, width, height, null, null);
        g2d.dispose();

        // 保存新图片
        ImageIO.write(image, fileType, outputStream);
    }

    public static void main(String[] args) throws Exception {
        ImageOperateUtil.convert("C:/Users/16/Desktop/image/mianju.jpg", "C:/Users/16/Desktop/image/mianju0.png");
        ImageOperateUtil.compress("C:/Users/16/Desktop/image/mianju.jpg", "C:/Users/16/Desktop/image/mianju1.jpg", 0.3f);
        ImageOperateUtil.crop("C:/Users/16/Desktop/image/mianju.jpg", "C:/Users/16/Desktop/image/mianju2.jpg", 3000, 2000);
        ImageOperateUtil.crop("C:/Users/16/Desktop/image/mianju.jpg", "C:/Users/16/Desktop/image/mianju3.jpg", 500, 500, 3000, 2000);
        ImageOperateUtil.reduceByRatio("C:/Users/16/Desktop/image/mianju.jpg", "C:/Users/16/Desktop/image/mianju4.jpg", 2);
        ImageOperateUtil.enlargeByRatio("C:/Users/16/Desktop/image/mianju.jpg", "C:/Users/16/Desktop/image/mianju5.jpg", 2);
        ImageOperateUtil.resize("C:/Users/16/Desktop/image/mianju.jpg", "C:/Users/16/Desktop/image/mianju6.jpg", 3000, 2000);
        ImageOperateUtil.gray("C:/Users/16/Desktop/image/mianju.jpg", "C:/Users/16/Desktop/image/mianju7.jpg");
        ImageOperateUtil.watermarkText("C:/Users/16/Desktop/image/mianju.jpg", "C:/Users/16/Desktop/image/mianju8.jpg",
                new Font("宋体", Font.BOLD, 150), new Color(255, 255, 255, 255), 300, 500, "哈哈哈哈");
        ImageOperateUtil.watermarkImage("C:/Users/16/Desktop/image/mianju.jpg", "C:/Users/16/Desktop/image/demo.jpeg",
                "C:/Users/16/Desktop/image/mianju9.jpg", 0, 0, 500, 500);
    }

}